package com.ddatsh.transaction.core.lifecycle.factory;

import static com.ddatsh.transaction.core.model.ApplicationContext.clonePropsToMap;
import static com.ddatsh.transaction.core.model.ApplicationContext.getTransDef;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.ddatsh.transaction.core.exception.ApplicationContextException;
import com.ddatsh.transaction.core.lifecycle.processunit.ProcessUnit;
import com.ddatsh.transaction.core.model.ApplicationErrorCode;
import com.ddatsh.transaction.core.model.Request;
import com.ddatsh.transaction.core.model.TransContext;
import com.ddatsh.transaction.core.model.TransactionDefinition;

/**
 * 交易上下文工厂类，用于创建交易上下文
 * 
 * @author ddatsh
 * @version 1.0
 */
public class TransContextFactory implements ApplicationContextAware {
	private ApplicationContext context = null;

	/**
	 * 创建交易上下文
	 * 
	 * @param request
	 *            请求包
	 * 
	 * @return 交易上下文
	 */
	public TransContext createTransContext(Request request) {
		String transCode = request.getTransCode();
		Properties systemProperty = clonePropsToMap();
		TransactionDefinition transdef = getTransDef(transCode);
		ProcessUnit[] transProcessUnits = this.generateProcessUnits(transCode);
		TransContext transContext = new TransContext(request, transdef,
				systemProperty, transProcessUnits);

		return transContext;
	}

	/**
	 * 创建交易上下文
	 * 
	 * @param request
	 *            请求包
	 * 
	 * @return 交易上下文
	 */
	public ProcessUnit[] generateProcessUnits(String tCode) {
		Map<String, ProcessUnit> allProcessUnits = context
				.getBeansOfType(ProcessUnit.class);
		List<ProcessUnit> processUnits = new ArrayList<ProcessUnit>();

		for (ProcessUnit pu : allProcessUnits.values()) {
			String transCode = pu.getTransCode();
			// 替换通配符为正则表达式匹配串
			String matchString = transCode.replace("*", "\\w*").replace("?",
					"\\w?");
			if (tCode.matches(matchString)) {
				processUnits.add(pu);
			}
		}

		Collections.sort(processUnits, new Comparator<ProcessUnit>() {
			public int compare(ProcessUnit processUnit1,
					ProcessUnit processUnit2) {
				int thisVal = processUnit1.getOrder();
				int anotherVal = processUnit2.getOrder();
				return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0
						: 1));
			}
		});

		if (processUnits.isEmpty()) {
			throw new ApplicationContextException(
					ApplicationErrorCode.APP_CONTEXT_EXCEPTION, "[" + tCode
							+ "] :processUnit Config is null！");
		}
		return processUnits.toArray(new ProcessUnit[0]);
	}

	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		this.context = context;
	}
}